package com.skivingcloud.camunda.controller;

import com.mybatisflex.core.paginate.Page;
import com.skivingcloud.admin.logutils.OperateLog;
import com.skivingcloud.admin.security.SecurityUser;
import com.skivingcloud.admin.utils.UserUtil;
import com.skivingcloud.camunda.constants.WorkflowConstants;
import com.skivingcloud.camunda.entity.ProcessDefinitionEntity;
import com.skivingcloud.camunda.entity.ProcessXmlVo;
import com.skivingcloud.camunda.service.ModelService;
import com.skivingcloud.common.exceptions.BusinessException;
import com.skivingcloud.common.utils.PageParameter;
import com.skivingcloud.common.utils.ReturnT;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

/**
 * 流程模型设计
 * @author hushouquan
 */
@RestController
@Tag(name = "流程模型设计")
@RequestMapping(WorkflowConstants.WORKFLOW_BASE_URL +"/model")
public class ModelController{
    protected static final Logger log = LoggerFactory.getLogger(ModelController.class);
    
    @Resource
    private ModelService modelService;
    
    /**
     * 查询模型列表
     * @param parameter 参数
     * @return 分页信息
     */
    @PostMapping("/list")
    @Operation(summary="分页查询通用业务数据表(业务的表单数据）")
    @PreAuthorize("hasAuthority('workflow:model:page')")
    public ReturnT<Page<ProcessDefinitionEntity>> list(@RequestBody @Parameter(description="分页信息") PageParameter<Map<String, Object>> parameter) {
        SecurityUser user = UserUtil.getCurrentUser();
        Page<ProcessDefinitionEntity> pageUtil = modelService.list(parameter, user);
        return ReturnT.ok(pageUtil);
    }
    
    /**
     * 根据id获取流程文件xml
     * @param id 流程定义id
     * @return 流程文件xml
     */
    @GetMapping("/getResourceByDefId/{id}")
    @Operation(summary="根据id获取流程文件xml")
    public ReturnT<String> getResourceByDefId(@PathVariable(name="id") String id){
        try{
            String resourceXml = modelService.getResourceByDefId(id);
            return ReturnT.ok(resourceXml);
        }catch(Exception e){
            log.error("获取流程文件内容失败", e);
            return ReturnT.error();
        }
    }
    
    /**
     * 发布流程
     * @param id 流程定义id
     * @return 结果
     */
    @OperateLog(module="系统管理-工作流-模板管理", description = "发布模型")
    @GetMapping("/deploy/{id}")
    @Operation(summary="发布流程")
    public ReturnT<String> deploy(@PathVariable("id") String id) {
        try {
            SecurityUser user = UserUtil.getCurrentUser();
            modelService.deploy(id, user);
            return ReturnT.ok();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnT.error(e.getMessage());
        }
    }
    
    /**
     * 保存流程设计
     * @param xmlVo 流程设计内容
     * @return 保存状况
     */
    @OperateLog(module="系统管理-工作流-模板管理", description = "保存流程设计")
    @PostMapping("/saveProcessDefinition")
    @Operation(summary="保存流程设计")
    public ReturnT<String> saveProcessDefinition(@RequestBody ProcessXmlVo xmlVo){
        try {
            SecurityUser user = UserUtil.getCurrentUser();
            modelService.saveProcessDefinition(xmlVo, user);
            return ReturnT.ok();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnT.error(e.getMessage());
        }
    }
    
    /**
     * 查询模型历史记录列表
     * @param parameter 参数
     * @return 分页信息
     */
    @PostMapping("/getModelDeployHisList")
    @Operation(summary="查询模型历史记录列表")
    public  ReturnT<Page<ProcessDefinitionEntity>> getModelDeployHisList(@RequestBody @Parameter(description="分页信息") PageParameter<Map<String, Object>> parameter) {
        if(!parameter.getParam().containsKey("key") || StringUtils.isBlank(parameter.getParam().get("key").toString())){
            return ReturnT.error("需要传入流程定义编号");
        }
        Page<ProcessDefinitionEntity> pageUtil = modelService.getModelDeployHisList(parameter);
        return ReturnT.ok(pageUtil);
    }
    
    /**
     * 根据部署id获取流程定义
     * @param deploymentId 流程部署id
     * @return 流程定义
     */
    @GetMapping("/getProcessDefinition/{deploymentId}")
    @Operation(summary="根据部署id获取流程定义")
    public ReturnT<ProcessDefinitionEntity> getProcessDefinition(@PathVariable(name="deploymentId") String deploymentId){
        try{
            ProcessDefinition m = modelService.getProcessDefinitionByDeploymentId(deploymentId);
            ProcessDefinitionEntity p = new ProcessDefinitionEntity();
            p.setId(m.getId());
            p.setName(m.getName());
            p.setDescription(m.getDescription());
            p.setKey(m.getKey());
            p.setVersion(m.getVersion());
            p.setCategory(m.getCategory());
            p.setDeploymentId(m.getDeploymentId());
            p.setResourceName(m.getResourceName());
            p.setDiagramResourceName(m.getDiagramResourceName());
            p.setHasStartFormKey(m.hasStartFormKey());
            p.setTenantId(m.getTenantId());
            p.setVersionTag(m.getVersionTag());
            p.setHistoryTimeToLive(m.getHistoryTimeToLive());
            p.setStartableInTasklist(m.isStartableInTasklist());
            return ReturnT.ok(p);
        }catch(Exception e){
            log.error("获取流程定义失败", e);
            return ReturnT.error();
        }
    }
    
    /**
     * 导出流程文件
     * @param deploymentId 部署id
     * @param request 请求体
     * @param response 返回体
     * @return 返回
     */
    @RequestMapping(value = "/export/{deploymentId}")
    @Operation(summary="导出流程文件")
    public ReturnT<String> resourceRead(@PathVariable("deploymentId") String deploymentId, HttpServletRequest request, HttpServletResponse response) {
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ProcessDefinition processDefinition = modelService.getProcessDefinitionByDeploymentId(deploymentId);
            
            if (processDefinition != null) {
                InputStream resourceAsStream = modelService.resourceRead(processDefinition.getId());
                byte[] b = new byte[1024];
                int len;
                // 配置文件下载
                response.setHeader("content-type", "application/octet-stream");
                response.setContentType("application/octet-stream");
                // 下载文件能正常显示中文
                response.setHeader("Content-Disposition", "attchement;filename=" + URLEncoder.encode(processDefinition.getResourceName(), StandardCharsets.UTF_8));
                while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
                    outputStream.write(b, 0, len);
                }
            } else {
                return ReturnT.error("导出失败");
            }
            
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ReturnT.error("导出失败");
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                } catch (Exception e) {
                    log.error("导出失败", e);
                }
            }
        }
        return null;
    }
    
    /**
     * 删除一个模型
     * @param id 流程定义id
     * @return 删除结果
     */
    @OperateLog(module="系统管理-工作流-模板管理", description = "删除流程模板")
    @GetMapping("/delete/{id}")
    @Operation(summary="删除一个模型")
    public ReturnT<String> remove(@PathVariable("id") String id) {
        try {
            modelService.deleteModel(id);
            return ReturnT.ok("删除成功");
        } catch (Exception e) {
            log.error("删除模型失败", e);
            return ReturnT.error("删除失败");
        }
    }
    
    /**
     * 流程导入
     * @param request request
     * @return 结果
     */
    @OperateLog(module="系统管理-工作流-模板管理", description = "导入流程")
    @PostMapping("/uploadModelFile")
    @Operation(summary="流程导入")
    public ReturnT<String> uploadModelFile(HttpServletRequest request) {
        StandardServletMultipartResolver resolver = new StandardServletMultipartResolver();
        MultipartHttpServletRequest mhr = resolver.resolveMultipart(request);
        List<MultipartFile> files = mhr.getFiles("file");
        SecurityUser user = UserUtil.getCurrentUser();
        try {
            modelService.importDeploy(files, user);
            return ReturnT.ok("导入成功");
        } catch (BusinessException e){
            return ReturnT.error(e.getMessage());
        } catch (Exception e) {
            log.error("部署失败", e);
            return ReturnT.error("部署失败！");
        }
    }
    
    /**
     * 获取流程信息
     * @return {code:,message:,data:{key:流程定义编码,value:流程名称}}
     */
    @GetMapping("/getProcessDefKV")
    @Operation(summary="获取流程信息")
    public ReturnT<List<Map<String, String>>> getProcessDefKV() {
        List<Map<String, String>> list = modelService.getProcessDefKV();
        return ReturnT.ok(list);
    }
}
